package eda.util;

public class HashingUtil<K, V> {
	
	private double multiplicationConstant = (double)(Math.sqrt(5) - 1)/2;

	/**
	 * Changes the String representation of the table by inserting an element
	 * so it can be used in the test to compare the expected table with the actual one.
	 * @param toString the String representation of the table
	 * @param key the key of the element to be inserted
	 * @param value the value of the element to be inserted
	 * @param tableLength the lenght of the table
	 * @return
	 */
	public String chainingInsertElement(String toString, K key, V value, int tableLength) {
		
		String newElement = "(" + key.toString() + ":" + value.toString() + ")";
		String lastPart = "";
		
		// Getting the position of the key in the table
		int pos = (int)Math.floor(tableLength*((key.hashCode()*multiplicationConstant ) % 1));
		
		if (pos < 0) {
			pos += tableLength;
		}
		
		for (int i = 2; i < toString.length(); i++) {
			// Looking for the right position in the table
			if ( toString.charAt(i) == '=' && toString.substring(i - 3, i).contains(Integer.toString(pos))) {
				// Verifying if there are or not other elements in this position
				if ((i + 5) != toString.length() - 1 && toString.charAt(i + 4) != ','  ) {
					i+= 4;
					while(toString.charAt(i) != ']') {
						i++;
					}
					
					lastPart = toString.substring(i);
					
					toString = toString.replace(lastPart, ", " + newElement);
					toString = toString.concat(lastPart);
					break;
				}  
			
				else {
					i+= 4;
					lastPart = toString.substring(i - 1);
					
					toString = toString.replace(lastPart, newElement);
					toString = toString.concat(lastPart);
					break;
				}
			}
		}
		
		return toString;
	}
	
	public String chainingRemoveElement(String toString, K key, V value, int tableLength) {
		
		String tableElement = "";
		String toBeRemoved = "(" + key.toString() + ":" + value.toString() + ")";
		String[] elementSplitted;
		String newElement = "";
		
		// Getting the position of the key in the table
		int pos = (int)Math.floor(tableLength*((key.hashCode()*multiplicationConstant ) % 1));
		
		if (pos < 0) {
			pos += tableLength;
		}
		
		for (int i = 2; i < toString.length(); i++) {
			// Looking for the right position in the table
			if ( toString.charAt(i) == '=' && toString.substring(i - 3, i).contains(Integer.toString(pos))) {
				// Verifying if there are or not other elements in this position
				
				// Case there is more than one element in the list
				if ((i + 5) != toString.length() - 1 && toString.charAt(i + 4) != ','  ) {
					i+= 3;
					
					while(toString.charAt(i) != ']') {
						tableElement += toString.charAt(i);
						i++;
					}
					
					
					elementSplitted = tableElement.split(",");
					
					int j = 0;
					
					while(! elementSplitted[j].contains(toBeRemoved)) {
						j++;
					}
					
					elementSplitted[j] = "";
					
					shiftLeft(elementSplitted, j);
					
					newElement += elementSplitted[0].trim() + ",";
					
					j = 1;
					
					while(j < elementSplitted.length - 1) {
						if (elementSplitted[j] != "") {
							newElement += elementSplitted[j] + ",";
						}
						else {
							newElement += elementSplitted[j];
						}
						j++;
					}
					
					newElement = newElement.substring(0, newElement.length() - 1);
					
					toString = toString.replace(tableElement, newElement);
					break;
				}
				
				// Case there is just one element in the list
				else {
					i+= 3;
					while(toString.charAt(i) != ']') {
						tableElement += toString.charAt(i);
						i++;
					}
					
					toString = toString.replace(tableElement, "");
					break;
				}
			}
		}
		
		return toString;
	}
	
	private String[] shiftLeft(String[] array, int index) {
		for (int i = index; i < array.length - 1; i++) {
			array[i] = array[i + 1];
		}
		
		array[array.length - 1] = "";
		
		return array;
	}

}
